/* Created by iflytek on 2020/03/01.
 *
 * 运行前：请先填写 appid、apiSecret、apiKey
 * 
 * 在线语音合成调用demo
 * 此demo只是一个简单的调用示例，不适合用到实际生产环境中
 *
 * 在线语音合成 WebAPI 接口调用示例 接口文档（必看）：https://www.xfyun.cn/doc/tts/online_tts/API.html
 * 错误码链接：
 * https://www.xfyun.cn/document/error-code （code返回错误码时必看）
 * 
 */
const CryptoJS = require('crypto-js')
const WebSocket = require('ws')

const fs = require('fs')
const status = require("../status");
const { configDir } = require("../unit");
const { existsSync, mkdirSync } = require("fs");
const { join } = require("path");
// const audioPlayer = require("../audioPlayer");
const audioPlayer = require("play-sound")(opts = {});
const logger = require("../logger");

// 系统配置 
const config = {
    // 请求地址
    hostUrl: "wss://tts-api.xfyun.cn/v2/tts",
    host: "tts-api.xfyun.cn",
    //在控制台-我的应用-在线语音合成（流式版）获取
    appid: "997a75b8",
    //在控制台-我的应用-在线语音合成（流式版）获取
    apiSecret: "YTdkZmYwNzFhNDlhOWUyMmZhZDkwNjA1",
    //在控制台-我的应用-在线语音合成（流式版）获取
    apiKey: "86c8ce67c89f9fadbfb791d79eb967ee",
    text: "这是一个例子，请输入您要合成的文本",
    uri: "/v2/tts",
}
var ttsConfig = {}
let ws = null
let isPlaying = false;


if (!existsSync(`${configDir}/tts`)) {
  mkdirSync(`${configDir}/tts`);
}

// 鉴权签名
function getAuthStr(date) {
  let signatureOrigin = `host: ${config.host}\ndate: ${date}\nGET ${config.uri} HTTP/1.1`
  let signatureSha = CryptoJS.HmacSHA256(signatureOrigin, config.apiSecret)
  let signature = CryptoJS.enc.Base64.stringify(signatureSha)
  let authorizationOrigin = `api_key="${config.apiKey}", algorithm="hmac-sha256", headers="host date request-line", signature="${signature}"`
  let authStr = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(authorizationOrigin))
  return authStr
}


const openWs = () => {
  if (ws && ws.readyState === WebSocket.OPEN) {
    logger.warn("Websocket 已初始化!")
    return ws
  }
  logger.warn("Websocket 初始化!")
  // 获取当前时间 RFC1123格式
  let date = (new Date().toUTCString())
  // 设置当前临时状态为初始化
  let wssUrl = config.hostUrl + "?authorization=" + getAuthStr(date) + "&date=" + date + "&host=" + config.host
  ws = new WebSocket(wssUrl)
  // 连接建立完毕，读取数据进行识别
  ws.on('open', () => {
    logger.warn("Websocket Open!")
  })
  // 得到结果后进行处理，仅供参考，具体业务具体对待
  ws.on('message', (data, err) => {
    if (err) {
        logger.error('Websocket Message error: ' + err)
        return
    }
    let res = JSON.parse(data)
    if (res.code != 0) {
        logger.error(`${res.code}: ${res.message}`)
        ws.close()
        return
    }
    let audio = res.data.audio
    let audioBuf = Buffer.from(audio, 'base64')
    // 保存文件
    const {options: options, ttsFilePath: ttsFilePath} = ttsConfig
    const { stop = false } = options;
    // const stop = false
    const filePath = ttsFilePath
    fs.writeFile(filePath, audioBuf, { flag: 'w' }, (err) => {
      if (err) {
          logger.error('save error: ' + err)
          return 
      }
      logger.warn('保存成功:' + filePath)
      // Play the audio file after saving
      if (!isPlaying) {
        isPlaying = true;
        audioPlayer.play(filePath, function(err) {
          isPlaying = false;
          if (err) {
            logger.error('播放失败: ' + err);
          } else {
            logger.warn('播放完成:' + filePath);
          }
        });
      }
    })
  })
  // 资源释放
  ws.on('close', () => { 
    logger.error('WebSocket Close!') 
    isPlaying = false;
  })
  ws.on('error', (err) => { 
    logger.error("WebSocket Connect err: " + err) 
    isPlaying = false;
  })
  return ws
}


const sendWs = (text) => {
  if (ws && ws.readyState === WebSocket.CONNECTING) {
    logger.info("WebSocket CONNECTING!")
    setTimeout(function () {
      sendWs(text);
    }, 300);
    return null
  } else if (ws && ws.readyState === WebSocket.CLOSED) {
    logger.error("WebSocket CLOSED!")
    openWs()
    setTimeout(function () { sendWs(text); }, 300);
    return null
  } else if (!ws) {
    logger.info("WebSocket NULL!")
    openWs()
    setTimeout(function () { sendWs(text); }, 300);
    return null
  }
  ws.send(JSON.stringify(text))
  logger.debug(`TTS Send: ${JSON.stringify(text)}`);
}


const tts = (text, ttsConfig) => {
  return new Promise((resolve, reject) => {
    let frame = {
      // 填充business
      "business": {
          "aue": "lame", //raw||lame
          "auf": "audio/L16;rate=16000",
          "vcn": "xiaoyan",
          "tte": "UTF8"
      },
      // 填充common
      "common": {"app_id": config.appid},
      // 填充data
      "data": {"text": Buffer.from(text).toString('base64'), "status": 2}
    }
    sendWs(frame)
  });
};


const speak = async (text = "一起玩网络遥控车", options = {}) => {
  logger.warn("TTS Play: " + text);
  if (status.argv && !status.argv.tts) {
    logger.info("未开启 TTS");
    return;
  }

  // const { time = 1, reg = "0", stop = false } = options;
  const filePath = join(`${configDir}/tts/`, text) + ".mp3";
  ttsConfig = {options: options, ttsFilePath: filePath}
  try {
    logger.info(`TTS Sdk: ${text} ==> "${filePath}"`);
    await tts(text, ttsConfig);
  } catch (e) {
    logger.error(`TTS Error: ${e.message}`);
  }
};
speak.tts = tts;
module.exports = speak;